/*
 * @(#)JideBorderLayout.java
 *
 * Copyright 2002 JIDE Software Inc. All rights reserved.

 * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package com.jidesoft.swing;

import java.awt.*;

/**
 * 这是 <code>BorderLayout</code> 的一个改进版. 不同于 <code>BorderLayout</code>,
 * 它头部和底部组件的宽度与中间组件的宽度是一样的. 在 BorderLayout中, 它们的宽度是和容器的宽度是一样的.
 *
 * @see BorderLayout
 */

public class JideBorderLayout implements LayoutManager2, java.io.Serializable {
	/**
	 * 构建边界布局的组件间的水平间隔. 水平间隔由 <code>hgap</code> 指定.
	 *
	 * @serial
	 * @see #getHgap()
	 * @see #setHgap(int)
	 */
	int hgap;

	/**
	 * 构建边界布局的组件间的垂直间隔. The 垂直间隔由 <code>vgap</code> 指定.
	 *
	 * @serial
	 * @see #getVgap()
	 * @see #setVgap(int)
	 */
	int vgap;

	/**
	 * 指定组件位置到边界布局北部的常量.
	 *
	 * @serial
	 * @see #getChild(String, boolean)
	 * @see #addLayoutComponent
	 * @see #getLayoutAlignmentX
	 * @see #getLayoutAlignmentY
	 * @see #removeLayoutComponent
	 */
	Component north;
	/**
	 * 指定组件位置到边界布局西部的常量.
	 *
	 * @serial
	 * @see #getChild(String, boolean)
	 * @see #addLayoutComponent
	 * @see #getLayoutAlignmentX
	 * @see #getLayoutAlignmentY
	 * @see #removeLayoutComponent
	 */
	Component west;
	/**
	 * 指定组件位置到边界布局东部的常量.
	 *
	 * @serial
	 * @see #getChild(String, boolean)
	 * @see #addLayoutComponent
	 * @see #getLayoutAlignmentX
	 * @see #getLayoutAlignmentY
	 * @see #removeLayoutComponent
	 */
	Component east;
	/**
	 * 指定组件位置到边界布局南部的常量.
	 *
	 * @serial
	 * @see #getChild(String, boolean)
	 * @see #addLayoutComponent
	 * @see #getLayoutAlignmentX
	 * @see #getLayoutAlignmentY
	 * @see #removeLayoutComponent
	 */
	Component south;
	/**
	 * 指定组件位置到边界布局中间的常量.
	 *
	 * @serial
	 * @see #getChild(String, boolean)
	 * @see #addLayoutComponent
	 * @see #getLayoutAlignmentX
	 * @see #getLayoutAlignmentY
	 * @see #removeLayoutComponent
	 */
	Component center;

	/**
	 * 一个相对位置常量 , 可以替代north, south, east, west 或者center使用. 混合另个类型的常量可能导致不可预测的结果.
	 * 如果你同时使用两种类型, 优先使用相对常量. 例如, 如果你添加组件同时使用了 <code>NORTH</code> 和
	 * <code>BEFORE_FIRST_LINE</code> 约束在一个方向是 <code>LEFT_TO_RIGHT</code> 容器中,
	 * 只有 <code>BEFORE_FIRST_LINE</code> 将会生效. 同样适用 lastLine, firstItem,
	 * lastItem.
	 *
	 * @serial
	 */
	Component firstLine;
	/**
	 * 一个相对位置常量 , 可以替代north, south, east, west 或者center使用. 请阅读 firstLine 的描述.
	 *
	 * @serial
	 */
	Component lastLine;
	/**
	 * 一个相对位置常量 , 可以替代north, south, east, west 或者center使用. 请阅读 firstLine 的描述.
	 *
	 * @serial
	 */
	Component firstItem;
	/**
	 * 一个相对位置常量 , 可以替代north, south, east, west 或者center使用. 请阅读 firstLine 的描述.
	 *
	 * @serial
	 */
	Component lastItem;

	/**
	 * 北布局约束 (容器的顶部).
	 */
	public static final String NORTH = "North";

	/**
	 * 南布局约束 (容器的底部).
	 */
	public static final String SOUTH = "South";

	/**
	 * 东布局约束 (容器的右边).
	 */
	public static final String EAST = "East";

	/**
	 * 西布局约束 (容器的左边).
	 */
	public static final String WEST = "West";

	/**
	 * 中间布局约束 (容器的中间).
	 */
	public static final String CENTER = "Center";

	/**
	 * 与 PAGE_START 同义. 保留以兼容以前的版本. 首选 PAGE_START .
	 *
	 * @see #PAGE_START
	 * @since 1.2
	 */
	public static final String BEFORE_FIRST_LINE = "First";

	/**
	 * 与 PAGE_END 同义. 保留以兼容以前的版本. 首选 PAGE_END .
	 *
	 * @see #PAGE_END
	 * @since 1.2
	 */
	public static final String AFTER_LAST_LINE = "Last";

	/**
	 * 与 LINE_START 同义. 保留以兼容以前的版本. 首选 LINE_START .
	 *
	 * @see #LINE_START
	 * @since 1.2
	 */
	public static final String BEFORE_LINE_BEGINS = "Before";

	/**
	 * 与 LINE_END 同义. 保留以兼容以前的版本. 首选 LINE_END .
	 *
	 * @see #LINE_END
	 * @since 1.2
	 */
	public static final String AFTER_LINE_ENDS = "After";

	/**
	 * 组件在布局内容的第一行之前. 对于西部, left-to-right 和 top-to-bottom 方向, 它等于 NORTH.
	 *
	 * @see java.awt.Component#getComponentOrientation
	 * @since 1.4
	 */
	public static final String PAGE_START = BEFORE_FIRST_LINE;

	/**
	 * 组件在布局内容的最后一行之后. 对于西部, left-to-right 和 top-to-bottom 方向, 它等于 SOUTH.
	 *
	 * @see java.awt.Component#getComponentOrientation
	 * @since 1.4
	 */
	public static final String PAGE_END = AFTER_LAST_LINE;

	/**
	 * 组件位于布局线方向的开始. 对于西部, left-to-right 和 top-to-bottom 方向, 它等于 WEST.
	 *
	 * @see java.awt.Component#getComponentOrientation
	 * @since 1.4
	 */
	public static final String LINE_START = BEFORE_LINE_BEGINS;

	/**
	 * 组件位于布局线方向的结束. 对于西部, left-to-right 和 top-to-bottom 方向, 它等于 EAST.
	 *
	 * @see java.awt.Component#getComponentOrientation
	 * @since 1.4
	 */
	public static final String LINE_END = AFTER_LINE_ENDS;

	/*
	 * JDK 1.1 serialVersionUID
	 */
	private static final long serialVersionUID = -8658291919501921765L;

	/**
	 * 构造一个组件间无间隔的边界布局.
	 */
	public JideBorderLayout() {
		this(0, 0);
	}

	/**
	 * 构造一个指定组件间间隔的边界布局. 水平间隔通过 <code>hgap</code> 指定, 垂直间隔通过 <code>vgap</code>
	 * 指定.
	 *
	 * @param hgap
	 *            水平间隔.
	 * @param vgap
	 *            垂直间隔.
	 */
	public JideBorderLayout(int hgap, int vgap) {
		this.hgap = hgap;
		this.vgap = vgap;
	}

	/**
	 * 返回组件间的水平间隔.
	 *
	 * @since JDK1.1
	 */
	public int getHgap() {
		return hgap;
	}

	/**
	 * 设置组件间的水平间隔.
	 *
	 * @param hgap
	 *            组件间的水平间隔.
	 * @since JDK1.1
	 */
	public void setHgap(int hgap) {
		this.hgap = hgap;
	}

	/**
	 * 返回组件间的垂直间隔.
	 *
	 * @since JDK1.1
	 */
	public int getVgap() {
		return vgap;
	}

	/**
	 * 设置组件间的垂直间隔.
	 *
	 * @param vgap
	 *            组件间的垂直间隔
	 * @since JDK1.1
	 */
	public void setVgap(int vgap) {
		this.vgap = vgap;
	}

	/**
	 * 添加指定的组件到布局中, 使用指定的约束物体. 对于边界布局, 约束必须是以下约束之一: <code>NORTH</code>,
	 * <code>SOUTH</code>, <code>EAST</code>, <code>WEST</code>, or
	 * <code>CENTER</code>.
	 * <p/>
	 * 大多数应用无需直接调用本方法. 当一个组件通过 <code>Container.add</code> 方法添加到容器中使用同样的参数类型,
	 * 本方法将会被调用.
	 *
	 * @param comp
	 *            待添加组件.
	 * @param constraints
	 *            指定物体添加到布局中的方式和位置的约束.
	 * @throws IllegalArgumentException
	 *             如果约束物体不是一个字符, 或者不是五个指定约束一直.
	 * @see java.awt.Container#add(java.awt.Component, java.lang.Object)
	 * @since JDK1.1
	 */
	public void addLayoutComponent(Component comp, Object constraints) {
		synchronized (comp.getTreeLock()) {
			if ((constraints == null) || (constraints instanceof String)) {
				addLayoutComponent((String) constraints, comp);
			} else {
				throw new IllegalArgumentException(
						"cannot add to layout: constraint must be a string (or null)");
			}
		}
	}

	/**
	 * @deprecated 已被 <code>addLayoutComponent(Component, Object)</code> 替代.
	 */
	@Deprecated
	public void addLayoutComponent(String name, Component comp) {
		synchronized (comp.getTreeLock()) {
			/* 特殊情况: 处理 null 为 "Center". */
			if (name == null) {
				name = "Center";
			}

			/*
			 * 排放组件到部局中已知的区域中.
			 */
			if ("Center".equals(name)) {
				center = comp;
			} else if ("North".equals(name)) {
				north = comp;
			} else if ("South".equals(name)) {
				south = comp;
			} else if ("East".equals(name)) {
				east = comp;
			} else if ("West".equals(name)) {
				west = comp;
			} else if (BEFORE_FIRST_LINE.equals(name)) {
				firstLine = comp;
			} else if (AFTER_LAST_LINE.equals(name)) {
				lastLine = comp;
			} else if (BEFORE_LINE_BEGINS.equals(name)) {
				firstItem = comp;
			} else if (AFTER_LINE_ENDS.equals(name)) {
				lastItem = comp;
			} else {
				throw new IllegalArgumentException(
						"cannot add to layout: unknown constraint: " + name);
			}
		}
	}

	/**
	 * 从边界布局中移除指定的组件. 这个方法当容器调用它的 <code>remove</code> 或者 <code>removeAll</code>
	 * 方法时被调用. 大多数应用无需直接调用此方法.
	 *
	 * @param comp
	 *            待删除的组件.
	 * @see java.awt.Container#remove(java.awt.Component)
	 * @see java.awt.Container#removeAll()
	 */
	public void removeLayoutComponent(Component comp) {
		synchronized (comp.getTreeLock()) {
			if (comp == center) {
				center = null;
			} else if (comp == north) {
				north = null;
			} else if (comp == south) {
				south = null;
			} else if (comp == east) {
				east = null;
			} else if (comp == west) {
				west = null;
			}
			if (comp == firstLine) {
				firstLine = null;
			} else if (comp == lastLine) {
				lastLine = null;
			} else if (comp == firstItem) {
				firstItem = null;
			} else if (comp == lastItem) {
				lastItem = null;
			}
		}
	}

	/**
	 * 获取添加时给定约束的组件
	 *
	 * @param constraints
	 *            期望的约束, <code>CENTER</code>, <code>NORTH</code>,
	 *            <code>SOUTH</code>, <code>WEST</code>, <code>EAST</code>,
	 *            <code>PAGE_START</code>, <code>PAGE_END</code>,
	 *            <code>LINE_START</code>, <code>LINE_END</code> 中一个
	 * @return 给定位置的组件, 或者 <code>null</code> 当位置为空时
	 *
	 * @throws IllegalArgumentException
	 *             如果约束物体不是九个指定约束之一
	 * @see #addLayoutComponent(java.awt.Component, java.lang.Object)
	 * @since 1.5
	 */
	public Component getLayoutComponent(Object constraints) {
		if (CENTER.equals(constraints)) {
			return center;
		} else if (NORTH.equals(constraints)) {
			return north;
		} else if (SOUTH.equals(constraints)) {
			return south;
		} else if (WEST.equals(constraints)) {
			return west;
		} else if (EAST.equals(constraints)) {
			return east;
		} else if (PAGE_START.equals(constraints)) {
			return firstLine;
		} else if (PAGE_END.equals(constraints)) {
			return lastLine;
		} else if (LINE_START.equals(constraints)) {
			return firstItem;
		} else if (LINE_END.equals(constraints)) {
			return lastItem;
		} else {
			throw new IllegalArgumentException(
					"cannot get component: unknown constraint: " + constraints);
		}
	}

	/**
	 * 返回基于目标 <code>Container</code> 的组件方向的符合给定约束位置的组件 . 以相对约束
	 * <code>PAGE_START</code>, <code>PAGE_END</code>, <code>LINE_START</code>,
	 * 和 <code>LINE_END</code> 添加的组件优先于以明确约束 <code>NORTH</code>,
	 * <code>SOUTH</code>, <code>WEST</code>, 和 <code>EAST</code> 添加的组件.
	 * <code>Container</code> 的组件方向用于定义以 <code>LINE_START</code> and
	 * <code>LINE_END</code> 约束添加的组件的位置.
	 *
	 * @param constraints
	 *            期望的绝对位置, <code>CENTER</code>, <code>NORTH</code>,
	 *            <code>SOUTH</code>, <code>EAST</code>, <code>WEST</code> 中一个
	 * @param target
	 *            {@code Container} 用于获取基于目标 {@code Container} 组件方向的约束位置.
	 * @return 给定位置的组件, 或者 <code>null</code> 当位置为空时
	 *
	 * @throws IllegalArgumentException
	 *             如果约束物体不是五个指定约束之一
	 * @throws NullPointerException
	 *             如果目标参数是 null
	 * @see #addLayoutComponent(java.awt.Component, java.lang.Object)
	 * @since 1.5
	 */
	public Component getLayoutComponent(Container target, Object constraints) {
		boolean ltr = target.getComponentOrientation().isLeftToRight();
		Component result = null;

		if (NORTH.equals(constraints)) {
			result = (firstLine != null) ? firstLine : north;
		} else if (SOUTH.equals(constraints)) {
			result = (lastLine != null) ? lastLine : south;
		} else if (WEST.equals(constraints)) {
			result = ltr ? firstItem : lastItem;
			if (result == null) {
				result = west;
			}
		} else if (EAST.equals(constraints)) {
			result = ltr ? lastItem : firstItem;
			if (result == null) {
				result = east;
			}
		} else if (CENTER.equals(constraints)) {
			result = center;
		} else {
			throw new IllegalArgumentException(
					"cannot get component: invalid constraint: " + constraints);
		}

		return result;
	}

	/**
	 * 获取指定组件的约束物体
	 *
	 * @param comp
	 *            待查询组件
	 * @return 指定组件的容器, 或者 null, 如果组件是 null 或者没有在布局中出现
	 *
	 * @see #addLayoutComponent(java.awt.Component, java.lang.Object)
	 * @since 1.5
	 */
	public Object getConstraints(Component comp) {
		// fix for 6242148 : API method
		// java.awt.BorderLayout.getConstraints(null) should return null
		if (comp == null) {
			return null;
		}
		if (comp == center) {
			return CENTER;
		} else if (comp == north) {
			return NORTH;
		} else if (comp == south) {
			return SOUTH;
		} else if (comp == west) {
			return WEST;
		} else if (comp == east) {
			return EAST;
		} else if (comp == firstLine) {
			return PAGE_START;
		} else if (comp == lastLine) {
			return PAGE_END;
		} else if (comp == firstItem) {
			return LINE_START;
		} else if (comp == lastItem) {
			return LINE_END;
		}
		return null;
	}

	/**
	 * 确定使用本布局管理器的 <code>target</code> 容器的最小尺寸.
	 * <p/>
	 * 本方法当容器调用它的 <code>getMinimumSize</code> 方法时被调用. 大多数应用无需直接调用本方法.
	 *
	 * @param target
	 *            需要排列的容器.
	 * @return 在指定的容器中放置子组件的最小尺寸.
	 *
	 * @see java.awt.Container
	 * @see java.awt.BorderLayout#preferredLayoutSize
	 * @see java.awt.Container#getMinimumSize()
	 */
	public Dimension minimumLayoutSize(Container target) {
		synchronized (target.getTreeLock()) {
			Dimension dim = new Dimension(0, 0);

			boolean ltr = target.getComponentOrientation().isLeftToRight();
			Component c = null;

			if ((c = getChild(CENTER, ltr)) != null) {
				Dimension d = c.getMinimumSize();
				dim.width += d.width;
				dim.height = Math.max(d.height, dim.height);
			}
			if ((c = getChild(NORTH, ltr)) != null) {
				Dimension d = c.getMinimumSize();
				dim.width = Math.max(d.width, dim.width);
				dim.height += d.height + vgap;
			}
			if ((c = getChild(SOUTH, ltr)) != null) {
				Dimension d = c.getMinimumSize();
				dim.width = Math.max(d.width, dim.width);
				dim.height += d.height + vgap;
			}
			if ((c = getChild(EAST, ltr)) != null) {
				Dimension d = c.getMinimumSize();
				dim.width += d.width + hgap;
				dim.height = Math.max(d.height, dim.height);
			}
			if ((c = getChild(WEST, ltr)) != null) {
				Dimension d = c.getMinimumSize();
				dim.width += d.width + hgap;
				dim.height = Math.max(d.height, dim.height);
			}

			Insets insets = target.getInsets();
			dim.width += insets.left + insets.right;
			dim.height += insets.top + insets.bottom;

			return dim;
		}
	}

	/**
	 * <code>target</code> 容器使用布局管理器的首选尺寸大小 , 基于容器中的组件.
	 * <p/>
	 * 大多数应用无需直接调用本方法. 本方法当容器调用它的 <code>getPreferredSize</code> 方法时被调用.
	 *
	 * @param target
	 *            需要排列的容器.
	 * @return 在指定的容器中放置子组件的首选尺寸.
	 *
	 * @see java.awt.Container
	 * @see java.awt.BorderLayout#minimumLayoutSize
	 * @see java.awt.Container#getPreferredSize()
	 */
	public Dimension preferredLayoutSize(Container target) {
		synchronized (target.getTreeLock()) {
			Dimension dim = new Dimension(0, 0);

			boolean ltr = target.getComponentOrientation().isLeftToRight();
			Component c = null;

			if ((c = getChild(CENTER, ltr)) != null) {
				Dimension d = c.getPreferredSize();
				dim.width += d.width;
				dim.height = Math.max(d.height, dim.height);
			}
			if ((c = getChild(NORTH, ltr)) != null) {
				Dimension d = c.getPreferredSize();
				dim.width = Math.max(d.width, dim.width);
				dim.height += d.height + vgap;
			}
			if ((c = getChild(SOUTH, ltr)) != null) {
				Dimension d = c.getPreferredSize();
				dim.width = Math.max(d.width, dim.width);
				dim.height += d.height + vgap;
			}
			if ((c = getChild(EAST, ltr)) != null) {
				Dimension d = c.getPreferredSize();
				dim.width += d.width + hgap;
				dim.height = Math.max(d.height, dim.height);
			}
			if ((c = getChild(WEST, ltr)) != null) {
				Dimension d = c.getPreferredSize();
				dim.width += d.width + hgap;
				dim.height = Math.max(d.height, dim.height);
			}

			Insets insets = target.getInsets();
			dim.width += insets.left + insets.right;
			dim.height += insets.top + insets.bottom;

			return dim;
		}
	}

	/**
	 * 返回指定目标容器中给定组件的最大尺寸.
	 *
	 * @param target
	 *            需要排列的容器.
	 * @see Container
	 * @see #minimumLayoutSize
	 * @see #preferredLayoutSize
	 */
	public Dimension maximumLayoutSize(Container target) {
		return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
	}

	/**
	 * 返回 x 轴向的准线. 这将指定组件的添加方式以使它与其他相对组件对齐. 值可以是 0 和 1 之间的一个数值, 0 代表与原点对齐, 1
	 * 代表与原点最远处对齐, 0.5 为中间, 等等.
	 */
	public float getLayoutAlignmentX(Container parent) {
		return 0.5f;
	}

	/**
	 * 返回 y 轴向的准线. 这将指定组件的添加方式以使它与其他相对组件对齐. 值可以是 0 和 1 之间的一个数值, 0 代表与原点对齐, 1
	 * 代表与原点最远处对齐, 0.5 为中间, 等等.
	 */
	public float getLayoutAlignmentY(Container parent) {
		return 0.5f;
	}

	/**
	 * 作废布局, 布局管理器的缓存信息将会被丢弃.
	 */
	public void invalidateLayout(Container target) {
	}

	/**
	 * 使用边界布局排列参数容器.
	 * <p/>
	 * 本方法会在指定的容器中重新排列组件, 为了满足 <code>BorderLayout</code> 物体的约束.
	 * <code>NORTH</code> 和 <code>SOUTH</code> 组件, 如果有的话, 将会被分别放置在容器的顶部和底部.
	 * <code>WEST</code> 和 <code>EAST</code> 组件然后被分别放置在左和右. 最后,
	 * <code>CENTER</code> 物体会被放置到中间任何剩余的空间中.
	 * <p/>
	 * 大多数应用无需直接调用本方法. 当容器调用它的 <code>doLayout</code> 方法时本方法被调用.
	 *
	 * @param target
	 *            待排列的容器.
	 * @see java.awt.Container
	 * @see java.awt.Container#doLayout()
	 */
	public void layoutContainer(Container target) {
		synchronized (target.getTreeLock()) {
			Insets insets = target.getInsets();
			int top = insets.top;
			int bottom = target.getHeight() - insets.bottom;
			int left = insets.left;
			int right = target.getWidth() - insets.right;

			boolean ltr = target.getComponentOrientation().isLeftToRight();

			Component north = getChild(NORTH, ltr);
			Component south = getChild(SOUTH, ltr);
			Component east = getChild(EAST, ltr);
			Component west = getChild(WEST, ltr);
			Component center = getChild(CENTER, ltr);

			/*
			 * Include the hgap here since if the east or west components do not
			 * exist then there should be no gap applied
			 */
			int westGap = (west != null ? west.getPreferredSize().width + hgap
					: 0);
			int eastGap = (east != null ? east.getPreferredSize().width + hgap
					: 0);

			if (north != null) {
				// north.setSize(right - left - westGap - eastGap/* - 2 *
				// hgap*/, north.getHeight());
				Dimension d = north.getPreferredSize();
				north.setBounds(left + westGap/* + hgap */, top, right - left
						- westGap - eastGap/* - 2 * hgap */, d.height);
				top += d.height + vgap;
			}
			if (south != null) {
				// south.setSize(right - left - westGap - eastGap/* - 2 *
				// hgap*/, south.getHeight());
				Dimension d = south.getPreferredSize();
				south.setBounds(left + westGap/* + hgap */, bottom - d.height,
						right - left - westGap - eastGap/* - 2 * hgap */,
						d.height);
				bottom -= d.height + vgap;
			}
			if (east != null) {
				east.setSize(east.getWidth(), bottom - top);
				Dimension d = east.getPreferredSize();
				east.setBounds(right - d.width, top, d.width, bottom - top);
				right -= d.width + hgap;
			}
			if (west != null) {
				west.setSize(west.getWidth(), bottom - top);
				Dimension d = west.getPreferredSize();
				west.setBounds(left, top, d.width, bottom - top);
				left += d.width + hgap;
			}
			if (center != null) {
				center.setBounds(left, top, right - left, bottom - top);
			}
		}
	}

	/**
	 * 获取与给定约束位置一致的组件
	 *
	 * @param key
	 *            期望的绝对位置, NORTH, SOUTH, EAST, 或者 WEST.
	 * @param ltr
	 *            组件的线方向是否是 left-to-right?
	 */
	private Component getChild(String key, boolean ltr) {
		Component result = null;

		if (key == NORTH) {
			result = (firstLine != null) ? firstLine : north;
		} else if (key == SOUTH) {
			result = (lastLine != null) ? lastLine : south;
		} else if (key == WEST) {
			result = ltr ? firstItem : lastItem;
			if (result == null) {
				result = west;
			}
		} else if (key == EAST) {
			result = ltr ? lastItem : firstItem;
			if (result == null) {
				result = east;
			}
		} else if (key == CENTER) {
			result = center;
		}
		if (result != null && !result.isVisible()) {
			result = null;
		}
		return result;
	}

	/**
	 * 返回此边界布局状态的字符描述.
	 *
	 * @return 此边界布局状态的字符描述.
	 */
	public String toString() {
		return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
	}
}
